config: &'a mut Config<'a>) -> CargoResult<PackageRegistry<'a>> {
let mut reg = PackageRegistry::empty(config);
+ let source_ids = dedup(source_ids);
for id in source_ids.iter() {
try!(reg.load(id, false));
// Get the summaries
for summary in (try!(source.list())).iter() {
- assert!(!dst.contains(summary), "duplicate summaries");
+ assert!(!dst.contains(summary), "duplicate summaries: {}", summary);
dst.push(summary.clone());
// self.summaries.push(summary.clone());
}
}
}
+fn dedup(ids: Vec<SourceId>) -> Vec<SourceId> {
+ let mut seen = vec!();
+
+ for id in ids.move_iter() {
+ if seen.contains(&id) { continue; }
+ seen.push(id);
+ }
+
+ seen
+}
+
impl<'a> Registry for PackageRegistry<'a> {
fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
let overrides = try!(self.overrides.query(dep)); // this can never fail in practice
use std::collections::HashSet;
-use std::io::File;
+use std::io::{File, fs};
use util;
use core::{Package,Manifest,SourceId};
-use util::{CargoResult, human, important_paths};
+use util::{CargoResult, human};
+use util::important_paths::find_project_manifest_exact;
pub fn read_manifest(contents: &[u8], source_id: &SourceId)
-> CargoResult<(Manifest, Vec<Path>)>
Ok((Package::new(manifest, path, source_id), nested))
}
-pub fn read_packages(path: &Path, source_id: &SourceId)
- -> CargoResult<Vec<Package>>
+pub fn read_packages(path: &Path,
+ source_id: &SourceId) -> CargoResult<Vec<Package>>
{
- return read_packages(path, source_id, &mut HashSet::new());
+ let mut all_packages = Vec::new();
+ let mut visited = HashSet::<Path>::new();
- fn read_packages(path: &Path, source_id: &SourceId,
- visited: &mut HashSet<Path>) -> CargoResult<Vec<Package>> {
- if !visited.insert(path.clone()) { return Ok(Vec::new()) }
+ log!(5, "looking for root package: {}, source_id={}", path.display(), source_id);
+ try!(process_possible_package(path, &mut all_packages, source_id, &mut visited));
- let manifest = try!(important_paths::find_project_manifest_exact(path,
- "Cargo.toml"));
- let (pkg, nested) = try!(read_package(&manifest, source_id));
- let mut ret = vec![pkg];
+ try!(walk(path, true, |dir| {
+ log!(5, "looking for child package: {}", dir.display());
+ if dir.filename_str() == Some(".git") { return Ok(false); }
+ if dir.join(".git").is_dir() { return Ok(false); }
+ try!(process_possible_package(dir, &mut all_packages, source_id, &mut visited));
+ Ok(true)
+ }));
- for p in nested.iter() {
- ret.push_all(try!(read_packages(&path.join(p),
- source_id,
- visited)).as_slice());
+ if all_packages.is_empty() {
+ Err(human(format!("Could not find Cargo.toml in `{}`", path.display())))
+ } else {
+ log!(5, "all packages: {}", all_packages);
+ Ok(all_packages)
+ }
+}
+
+fn walk(path: &Path, is_root: bool, callback: |&Path| -> CargoResult<bool>) -> CargoResult<()> {
+ if path.is_dir() {
+ if !is_root {
+ let continues = try!(callback(path));
+ if !continues { log!(5, "Found submodule at {}", path.display()); return Ok(()); }
}
- Ok(ret)
+ for dir in try!(fs::readdir(path)).iter() {
+ try!(walk(dir, false, |x| callback(x)))
+ }
+ }
+
+ Ok(())
+}
+
+fn process_possible_package(dir: &Path,
+ all_packages: &mut Vec<Package>,
+ source_id: &SourceId,
+ visited: &mut HashSet<Path>) -> CargoResult<()> {
+
+ if !has_manifest(dir) { return Ok(()); }
+
+ let packages = try!(read_nested_packages(dir, source_id, visited));
+ push_all(all_packages, packages);
+
+ Ok(())
+}
+
+fn has_manifest(path: &Path) -> bool {
+ find_project_manifest_exact(path, "Cargo.toml").is_ok()
+}
+
+fn read_nested_packages(path: &Path, source_id: &SourceId,
+ visited: &mut HashSet<Path>) -> CargoResult<Vec<Package>> {
+ if !visited.insert(path.clone()) { return Ok(Vec::new()) }
+
+ let manifest = try!(find_project_manifest_exact(path, "Cargo.toml"));
+
+ let (pkg, nested) = try!(read_package(&manifest, source_id));
+ let mut ret = vec![pkg];
+
+ for p in nested.iter() {
+ ret.push_all(try!(read_nested_packages(&path.join(p),
+ source_id,
+ visited)).as_slice());
+ }
+
+ Ok(ret)
+}
+
+fn push_all(set: &mut Vec<Package>, packages: Vec<Package>) {
+ for package in packages.move_iter() {
+ if set.contains(&package) { continue; }
+
+ set.push(package)
}
}
cargo::util::process(project.bin("foo")),
execs().with_stdout("hello world\n"));
})
+
test!(cargo_compile_with_nested_paths {
let git_project = git_repo("dep1", |project| {
project
execs().with_stdout("hello world\n"));
})
+test!(cargo_compile_with_meta_package {
+ let git_project = git_repo("meta-dep", |project| {
+ project
+ .file("dep1/Cargo.toml", r#"
+ [project]
+
+ name = "dep1"
+ version = "0.5.0"
+ authors = ["carlhuda@example.com"]
+
+ [[lib]]
+
+ name = "dep1"
+ "#)
+ .file("dep1/src/dep1.rs", r#"
+ pub fn hello() -> &'static str {
+ "this is dep1"
+ }
+ "#)
+ .file("dep2/Cargo.toml", r#"
+ [project]
+
+ name = "dep2"
+ version = "0.5.0"
+ authors = ["carlhuda@example.com"]
+
+ [[lib]]
+
+ name = "dep2"
+ "#)
+ .file("dep2/src/dep2.rs", r#"
+ pub fn hello() -> &'static str {
+ "this is dep2"
+ }
+ "#)
+ }).assert();
+
+ let p = project("parent")
+ .file("Cargo.toml", format!(r#"
+ [project]
+
+ name = "parent"
+ version = "0.5.0"
+ authors = ["wycats@example.com"]
+
+ [dependencies.dep1]
+
+ version = "0.5.0"
+ git = "file:{}"
+
+ [dependencies.dep2]
+
+ version = "0.5.0"
+ git = "file:{}"
+
+ [[bin]]
+
+ name = "parent"
+ "#, escape_path(&git_project.root()), escape_path(&git_project.root())))
+ .file("src/parent.rs",
+ main_file(r#""{} {}", dep1::hello(), dep2::hello()"#, ["dep1", "dep2"]).as_slice());
+
+ p.cargo_process("cargo-build")
+ .exec_with_output()
+ .assert();
+
+ assert_that(&p.bin("parent"), existing_file());
+
+ assert_that(
+ cargo::util::process(p.bin("parent")),
+ execs().with_stdout("this is dep1 this is dep2\n"));
+})
+
test!(cargo_compile_with_short_ssh_git {
let url = "git@github.com:a/dep";